package libs

import "sync"

// chan  + sync 实现 控制并发数量

/**
利
适合量不大、复杂度低的使用场景
几百几千个、几十万个也是可以接受的（看具体业务场景）
实际业务逻辑在运行前就已经被阻塞等待了（因为并发数受限），基本实际业务逻辑损耗的性能比 goroutine 本身大
goroutine 本身很轻便，仅损耗极少许的内存空间和调度。这种等待响应的情况都是躺好了，等待任务唤醒
Semaphore 操作复杂度低且流转简单，容易控制
弊
不适合量很大、复杂度高的使用场景
有几百万、几千万个 goroutine 的话，就浪费了大量调度 goroutine 和内存空间。恰好你的服务器也接受不了的话
Semaphore 操作复杂度提高，要管理更多的状态
*/
type Semaphore struct {
	c  chan struct{}
	wg *sync.WaitGroup
}

func NewSemaphore(maxSize int) *Semaphore {
	return &Semaphore{
		c:  make(chan struct{}, maxSize),
		wg: new(sync.WaitGroup),
	}
}
func (s *Semaphore) Add(delta int) {
	s.wg.Add(delta)
	for i := 0; i < delta; i++ {
		s.c <- struct{}{}
	}
}
func (s *Semaphore) Done() {
	<-s.c
	s.wg.Done()
}
func (s *Semaphore) Wait() {
	s.wg.Wait()
}
